Vue源码 编译(四)codegen 把优化后的 AST 树转换成可执行的代码

您所在的位置:网站首页 代码编译后变成 可执行 Vue源码 编译(四)codegen 把优化后的 AST 树转换成可执行的代码

Vue源码 编译(四)codegen 把优化后的 AST 树转换成可执行的代码

2024-07-06 05:07| 来源: 网络整理| 查看: 265

Vue源码 编译(四)把优化后的 AST 树转换成可执行的代码 Vue源码 编译(四)把优化后的 AST 树转换成可执行的代码codegen单步调试代码generate`genIf``genFor``genData` & `genChildren`总结 Vue源码学习目录

Vue源码 编译(四)把优化后的 AST 树转换成可执行的代码

学习内容和文章内容来自 黄轶老师 黄轶老师的慕课网视频教程地址:《Vue.js2.0 源码揭秘》、 黄轶老师拉钩教育教程地址:《Vue.js 3.0 核心源码解析》 这里分析的源码是Runtime + Compiler 的 Vue.js 调试代码在:node_modules\vue\dist\vue.esm.js 里添加 vue版本:Vue.js 2.5.17-beta

你越是认真生活,你的生活就会越美好——弗兰克·劳埃德·莱特 《人生果实》经典语录

点击回到 Vue源码学习完整目录

Vue源码 编译(一)编译入口 我们找到的编译的入口,它主要就是执行了如下几个逻辑:

解析模板字符串生成 AST const ast = parse(template.trim(), options) 优化语法树 optimize(ast, options) 生成代码 const code = generate(ast, options) codegen 单步调试代码 // src/main.js import Vue from 'vue' new Vue({ el: '#app', template: ` {{item}}:{index}} {{item}}:{{index}}

它经过编译,执行 const code = generate(ast, options),生成的 render 代码串如下:

with(this){ return (isShow) ? _c('ul', { staticClass: "list", class: bindCls }, _l((data), function(item, index) { return _c('li', { on: { "click": function($event) { clickItem(index) } } }, [_v(_s(item) + ":" + _s(index))]) }) ) : _e() }

在这里插入图片描述

这里的 _c 函数定义在 src/core/instance/render.js 中。

vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)

而 _l、_v 定义在 src/core/instance/render-helpers/index.js 中:

export function installRenderHelpers (target: any) { target._o = markOnce target._n = toNumber target._s = toString target._l = renderList target._t = renderSlot target._q = looseEqual target._i = looseIndexOf target._m = renderStatic target._f = resolveFilter target._k = checkKeyCodes target._b = bindObjectProps target._v = createTextVNode target._e = createEmptyVNode target._u = resolveScopedSlots target._g = bindObjectListeners }

顾名思义,

_c 就是执行 createElement 去创建 VNode,_l 对应 renderList 渲染列表,;_v 对应 createTextVNode 创建文本 VNode;_e 对于 createEmptyVNode创建空的 VNode。

在 compileToFunctions 中,会把这个 render 代码串转换成函数,它的定义在 src/compler/to-function.js 中:

const compiled = compile(template, options) res.render = createFunction(compiled.render, fnGenErrors) function createFunction (code, errors) { try { return new Function(code) } catch (err) { errors.push({ err, code }) return noop } }

在这里插入图片描述

实际上就是把 render 代码串通过 new Function 的方式转换成可执行的函数,赋值给 vm.options.render,这样当组件通过 vm._render 的时候,就会执行这个 render 函数。

那么接下来我们就重点关注一下这个 render 代码串的生成过程。

generate const code = generate(ast, options)

generate 函数的定义在 src/compiler/codegen/index.js 中:

export function generate ( ast: ASTElement | void, options: CompilerOptions ): CodegenResult { const state = new CodegenState(options) const code = ast ? genElement(ast, state) : '_c("div")' return { render: `with(this){return ${code}}`, staticRenderFns: state.staticRenderFns } }

在这里插入图片描述

generate 函数首先通过 genElement(ast, state) 生成 code,再把 code 用 with(this){return ${code}}} 包裹起来。

这里的 state 是 CodegenState 的一个实例,稍后我们在用到它的时候会介绍它。先来看一下 genElement:

export function genElement (el: ASTElement, state: CodegenState): string { if (el.staticRoot && !el.staticProcessed) { return genStatic(el, state) } else if (el.once && !el.onceProcessed) { return genOnce(el, state) } else if (el.for && !el.forProcessed) { return genFor(el, state) } else if (el.if && !el.ifProcessed) { return genIf(el, state) } else if (el.tag === 'template' && !el.slotTarget) { return genChildren(el, state) || 'void 0' } else if (el.tag === 'slot') { return genSlot(el, state) } else { // component or element let code if (el.component) { code = genComponent(el.component, el, state) } else { const data = el.plain ? undefined : genData(el, state) const children = el.inlineTemplate ? null : genChildren(el, state, true) code = `_c('${el.tag}'${ data ? `,${data}` : '' // data }${ children ? `,${children}` : '' // children })` } // module transforms for (let i = 0; i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3